/*
 * Copyright 2002-2016 the Beijing Brain Technology co.,LTD http://www.bris.cn/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bris.niosocket.handler.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

import java.nio.ByteBuffer;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bris.niosocket.message.Codecable;
import com.bris.niosocket.message.impl.ResponseMessage;
import com.bris.niosocket.message.util.CodeUtil;

/**
 * TODO 描述该类型的作用</br>
 * 2016年2月17日</br>
 * @author xunaidong
 * @since 1.0.0
 */
public class ResponseEncoder extends MessageToByteEncoder<ResponseMessage> implements Codecable{
	
	
	private final static Logger log = LoggerFactory.getLogger(ResponseEncoder.class);

	/* (non-Javadoc)
	 * @see com.bris.niosocket.message.Codecable#getEncoding()
	 */
	@Override
	public String getEncoding() {
		// TODO Auto-generated method stub
		return "UTF-8";
	}

	/* (non-Javadoc)
	 * @see io.netty.handler.codec.MessageToByteEncoder#encode(io.netty.channel.ChannelHandlerContext, java.lang.Object, io.netty.buffer.ByteBuf)
	 */
	@Override
	protected void encode(ChannelHandlerContext ctx, ResponseMessage msg,ByteBuf buffer) throws Exception {
		try{
			log.debug("************Encoding***********");
			log.debug("Netty provide buf is {}",buffer);
			int bodyLength = 0;//暂未确定报文体大小
			buffer.writeBytes(CodeUtil.intToBytes4(PACKET_LENGTH_FIELD_LEN + COMMAND_ID_LEN + bodyLength+msg.getSerialNumber().length()));
			buffer.writeBytes(CodeUtil.intToBytes4(msg.CMD_RESPONSE));
			buffer.writeBytes(msg.getSerialNumber().value().getBytes(getEncoding()));
			int bodyMark = buffer.writerIndex();//给即将编码报文体的起始位置打标记
			int bodyEndMark = bodyMark;//报文体结束写指针,默认为起始位置
			Map<String,String[]> store = msg.getValuesMap();
			if(store.size()!=0){
				buffer.writeByte(VERSION);
				int totalLength = ENCODE_BODY_PRFIX_LENGTH + store.size() * 6;//不包含VERSION的报文体长度
				buffer.writeBytes(CodeUtil.intToBytes4(totalLength));
				buffer.writeBytes(CodeUtil.short2Byte(STATUS));
				buffer.writeBytes(CodeUtil.unsignShort2Byte(store.size()));
				for (String key : store.keySet()) {
					byte[] key2byte = key.getBytes(getEncoding());
					totalLength += key2byte.length;
					buffer.writeBytes(CodeUtil.unsignShort2Byte(key2byte.length));
					buffer.writeBytes(key2byte);
					String[] values = store.get(key);
					int mark = buffer.writerIndex();
					buffer.writeBytes(CodeUtil.intToBytes4(mark));
					buffer.writeInt(values.length);
					for(String value:values){
						byte[] valueByte = value.getBytes(getEncoding());
						buffer.writeBytes(CodeUtil.intToBytes4(valueByte.length));
						buffer.writeBytes(valueByte);
					}
					int afterLoop = buffer.writerIndex(); 
					buffer.writerIndex(mark);
					buffer.writeBytes(CodeUtil.intToBytes4(afterLoop-mark-4));
					totalLength += afterLoop-mark-4;
					buffer.writerIndex(afterLoop);
					bodyEndMark = buffer.writerIndex();
					buffer.writerIndex(bodyMark+1);//重新设置报文体长度值
					buffer.writeBytes(CodeUtil.intToBytes4(totalLength));
					buffer.writerIndex(bodyEndMark);//复位写指针
				}
				bodyLength = bodyEndMark - bodyMark;//报文体长度
				if(bodyLength!=0){
					buffer.writerIndex(0);//写指针指向0;
					buffer.writeBytes(CodeUtil.intToBytes4(PACKET_LENGTH_FIELD_LEN + COMMAND_ID_LEN + bodyLength+msg.getSerialNumber().length()));//重新赋值报文长度
					buffer.writerIndex(bodyEndMark);//复位写指针
				}
				log.debug("编码后的netty buf is {}",buffer);
			}
		}catch(Exception e){
			log.error("Netty ResponseEncoder has error!",e);
			throw e;
		}
				
		
	}
	
	public void test(ResponseMessage msg) throws Exception {
		ByteBuffer buffer =  ByteBuffer.allocate(1024*3);
		int bodyLength = 0;//暂未确定报文体大小
		buffer.put(CodeUtil.intToBytes4(PACKET_LENGTH_FIELD_LEN + COMMAND_ID_LEN + bodyLength+msg.getSerialNumber().length()));
		buffer.put(CodeUtil.intToBytes4(msg.CMD_RESPONSE));
		buffer.put(msg.getSerialNumber().value().getBytes("utf-8"));
		int bodyMark = buffer.position();//给即将编码报文体的起始位置打标记
		int bodyEndMark = bodyMark;//报文体结束写指针,默认为起始位置
		Map<String,String[]> store = msg.getValuesMap();
		if(store.size()!=0){
			buffer.put(VERSION);
			int totalLength = ENCODE_BODY_PRFIX_LENGTH + store.size() * 6;//不包含VERSION的报文体长度
			buffer.put(CodeUtil.intToBytes4(totalLength));
			buffer.put(CodeUtil.short2Byte(STATUS));
			buffer.put(CodeUtil.unsignShort2Byte(store.size()));
			for (String key : store.keySet()) {
				byte[] key2byte = key.getBytes("UTF-8");
				totalLength += key2byte.length;
				buffer.put(CodeUtil.unsignShort2Byte(key2byte.length));
				buffer.put(key2byte);
				String[] values = store.get(key);
				int mark = buffer.position();
				buffer.put(CodeUtil.intToBytes4(mark));
				buffer.putInt(values.length);
				for(String value:values){
					byte[] valueByte = value.getBytes("UTF-8");
					buffer.put(CodeUtil.intToBytes4(valueByte.length));
					buffer.put(valueByte);
				}
				int afterLoop = buffer.position(); 
				buffer.position(mark);
				buffer.put(CodeUtil.intToBytes4(afterLoop-mark-4));
				totalLength += afterLoop-mark-4;
				buffer.position(afterLoop);
				bodyEndMark = buffer.position();
				buffer.position(bodyMark+1);//重新设置报文体长度值
				buffer.put(CodeUtil.intToBytes4(totalLength));
				buffer.position(bodyEndMark);//复位写指针
			}
			bodyLength = bodyEndMark - bodyMark;//报文体长度
			if(bodyLength!=0){
				buffer.position(0);//写指针指向0;
				System.out.println(PACKET_LENGTH_FIELD_LEN + COMMAND_ID_LEN + bodyLength+msg.getSerialNumber().length());
				buffer.put(CodeUtil.intToBytes4(PACKET_LENGTH_FIELD_LEN + COMMAND_ID_LEN + bodyLength+msg.getSerialNumber().length()));//重新赋值报文长度
				buffer.position(bodyEndMark);//复位写指针
			}
			buffer.flip();
			System.out.println(CodeUtil.getHexStr(buffer.array()));
		}
		log.debug("编码完成{}",buffer);
	}

}
